<?php
require_once('ezsqlcore.class.php');
$ezsql_pdo_str = array
(
	1 => 'Require $dsn and $user and $password to create a connection'
);

if ( ! class_exists ('PDO') ) die('<b>Fatal Error:</b> ezSQL_sqlite requires PDO Lib to be compiled and or linked in to the PHP engine');
if ( ! class_exists ('ezSQLcore') ) die('<b>Fatal Error:</b> ezSQL_sqlite requires ezSQLcore (ez_sql_core.php) to be included/loaded before it can be used');

class ezSQLPdo extends ezSQLcore
{
	protected $dsn;
	protected $user;
	protected $password;
	private static $instance=array();

	public function __construct($dsn='', $user='', $password='')
	{
		ini_set('track_errors',1);

		if ( $dsn && $user && $password )
		{
			$this->connect($dsn, $user, $password);
		}
		$this->query('SET NAMES UTF8');
	}
	
	static function getInstance($key)
	{
		if(!isset(self::$instance[$key]))
		{
			global $config;
			extract($config[$key]);
			$dsn = 'mysql:host=' . $host . ';dbname=' . $dbname;
			self::$instance[$key] = new ezSQLPdo($dsn,$user,$password); 	
		}
		return self::$instance[$key];
	}	
	/**
	 * connect db server
	 * @param string $dsn
	 * @param string $user
	 * @param string $password
	 * @return bool
	 */
	function connect($dsn='', $user='', $password='')
	{
		global $ezsql_pdo_str; $return_val = false;

		// Must have a user and a password
		if ( ! $dsn || ! $user || ! $password )
		{
			$this->registerError($ezsql_pdo_str[1].' in '.__FILE__.' on line '.__LINE__);
			$this->show_errors ? trigger_error($ezsql_pdo_str[1],E_USER_WARNING) : null;
		}
		try 
		{
			$this->dbh = new PDO($dsn, $user, $password);
			$return_val = true;
		} 
		catch (PDOException $e) 
		{
			$this->registerError($e->getMessage());
			$this->show_errors ? trigger_error($e->getMessage(),E_USER_WARNING) : null;
		}

		return $return_val;			
	}
	function quickConnect($dsn='', $user='', $password='')
	{
		return $this->connect($dsn, $user, $password);
	}

	function select($dsn='', $user='', $password='')
	{
		return $this->connect($dsn, $user, $password);
	}

	function escape($str)
	{
		switch (gettype($str))
		{
			case 'string' : 
				$str = addslashes(stripslashes($str));
				break;
			case 'boolean' :
				$str = ($str === FALSE) ? 0 : 1;
				break;
			default : 
				$str = ($str === NULL) ? 'NULL' : $str;
				break;
		}

		return $str;
	}

	function sysdate()
	{
		return "datetime('now')";			
	}

	private function catchError()
	{
		$error_str = 'No error info';

		$err_array = $this->dbh->errorInfo();

		// Note: Ignoring error - bind or column index out of range
		if ( isset($err_array[1]) && $err_array[1] != 25)
		{
			$error_str = '';
			foreach ( $err_array as $entry )
			{
				$error_str .= $entry . ', ';
			}
			$error_str = substr($error_str,0,-2);

			$this->registerError($error_str);
			$this->show_errors ? trigger_error($error_str.' '.$this->last_query,E_USER_WARNING) : null;

			return true;
		}

	}

	function query($query)
	{
		$query = str_replace("/[\n\r]/",'',trim($query)); 

		// initialise return
		$return_val = 0;

		$this->flush();
		$this->func_call = "\$db->query(\"$query\")";
		$this->last_query = $query;
		$this->num_queries++;

		$this->sqlLog($query);

		// Start timer
		$this->timerStart($this->num_queries);

		// Use core file cache function
		if ( $cache = $this->getCache($query) )
		{
			$this->timerUpdateGlobal($this->num_queries);
			if ( $this->use_trace_log )
			{
				$this->trace_log[] = $this->debug(false);
			}

			return $cache;
		}
		if ( ! isset($this->dbh) || ! $this->dbh )
		{
			$this->connect($this->dsn, $this->user, $this->password);
		}

		// Query was an insert, delete, update, replace
		if ( preg_match("/^(insert|delete|update|replace|drop|create)\s+/i",$query) )
		{		
			// Perform the query and log number of affected rows
			$this->rows_affected = $this->dbh->exec($query);

			// If there is an error then take note of it..
			if ( $this->catchError() )
			{
				$this->sqlLog($query,'error');
				return false;
			}

			$is_insert = true;

			// Take note of the insert_id
			if ( preg_match("/^(insert|replace)\s+/i",$query) )
			{
				$this->insert_id = @$this->dbh->lastInsertId();	
			}

			// Return number fo rows affected
			$return_val = $this->rows_affected;

		}
		// Query was an select
		else
		{

			// Perform the query and log number of affected rows
			$sth = $this->dbh->query($query);

			// If there is an error then take note of it..
			if ( $this->catchError() )
			{
				$this->sqlLog($query,'error');
				return false;
			}

			$is_insert = false;
			$col_count = $sth->columnCount();
			for ( $i=0 ; $i < $col_count ; $i++ )
			{
				if ( $meta = $sth->getColumnMeta($i) )
				{					
					$this->col_info[$i]->name =  $meta['name'];
					$this->col_info[$i]->type =  $meta['native_type'];
					$this->col_info[$i]->max_length =  '';
				}
				else
				{
					$this->col_info[$i]->name =  'undefined';
					$this->col_info[$i]->type =  'undefined';
					$this->col_info[$i]->max_length = '';
				}
			}

			$num_rows=0;
			while ( $row = @$sth->fetch(PDO::FETCH_ASSOC) )
			{
				// Store relults as an objects within main array
				//$this->last_result[$num_rows] = (object) $row;
				$this->last_result[$num_rows] = $row;
				$num_rows++;
			}

			$this->num_rows = $num_rows;
			// Return number of rows selected
			$return_val = $this->num_rows;
		}
		$this->storeCache($query,$is_insert);
		$this->trace || $this->debug_all ? $this->debug() : null ;
		$this->timerUpdateGlobal($this->num_queries);
		// Trace all queries
		if ( $this->use_trace_log )
		{
			$this->trace_log[] = $this->debug(false);
		}
		return $return_val;
	}
}
